from typing import List

from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from models.users import User
from models import AsyncSessionFactory
from schemas.users import CreateUserReqSchema, UserRespSchema, UpdateUserReqSchema
from fastapi.requests import Request
from sqlalchemy import select, delete, or_, update

router = APIRouter(prefix='/user', tags=['user'])


@router.post('/add', response_model=UserRespSchema)
async def add_user(user_data: CreateUserReqSchema):
    # # 1 不使用上下文管理器
    # session = AsyncSessionFactory()
    # # 自动创建一个事务
    # try:
    #     user = User(email=user_data.email, username=user_data.username, password=user_data.password)
    #     session.add(user)
    #     await session.commit()
    #     # await session.refresh(user, attribute_names=['id'])
    # except sqlalchemy.exc.IntegrityError as e:
    #     await session.rollback()
    #     raise HTTPException(status_code=400, detail=f'{e}')
    # await session.close()
    # return user

    # 2 用上下文管理器
    async with AsyncSessionFactory() as session:
        # 自动开启事务
        # try:
        #     user = User(email=user_data.email, username=user_data.username, password=user_data.password)
        #     session.add(user)
        #     await session.commit()
        # except sqlalchemy.exc.IntegrityError as e:
        #     await session.rollback()
        #     raise HTTPException(status_code=400, detail=f'{e}')

        # 手动开启事务
        try:
            async with session.begin():
                user = User(email=user_data.email, username=user_data.username, password=user_data.password)
                session.add(user)
                # 手动开启事务，在上下文中不需要手动commit
                # await session.commit()
        except Exception as e:
            # 如果抛出异常 上下文管理器会自动回滚
            # await session.rollback()
            raise HTTPException(status_code=400, detail=f'{e}')

    return user


async def get_session():
    session = AsyncSessionFactory()
    try:
        yield session
    finally:
        await session.close()


@router.post('/add/depends', response_model=UserRespSchema)
async def add_user_depends(
        user_data: CreateUserReqSchema,
        session: AsyncSession = Depends(get_session)
):
    try:
        async with session.begin():
            user = User(email=user_data.email, username=user_data.username, password=user_data.password)
            session.add(user)
            # 手动开启事务，在上下文中不需要手动commit
            # await session.commit()
        return user
    except Exception as e:
        # 如果抛出异常 上下文管理器会自动回滚
        # await session.rollback()
        raise HTTPException(status_code=400, detail=f'{e}')


@router.post('/add/middleware', response_model=UserRespSchema)
async def add_user_middleware(request: Request, user_data: CreateUserReqSchema):
    session = request.state.session
    try:
        async with session.begin():
            user = User(email=user_data.email, username=user_data.username, password=user_data.password)
            session.add(user)
        return user
    except Exception as e:
        # 如果抛出异常 上下文管理器会自动回滚
        raise HTTPException(status_code=400, detail=f'{e}')


@router.delete('/delete/{user_id}')
async def delete_user(user_id: int, request: Request):
    session = request.state.session
    async with session.begin():
        stmt = delete(User).where(User.id == user_id)
        await session.execute(stmt)
    return {"message": "删除成功"}


@router.get('/select/{user_id}', response_model=UserRespSchema)
async def select_user_one(user_id: int, request: Request):
    session = request.state.session
    async with session.begin():
        # 指定要查询的几个字段
        stmt = select(User.id, User.email, User.username).where(User.id == user_id)
        result = await session.execute(stmt)
        data = result.one()._asdict()
        return data

        # 直接把模型查出来
        # stmt = select(User).where(User.id == user_id)
        # result = await session.execute(stmt)
        # data = result.scalars().first()
        # return data


@router.get('/select', response_model=List[UserRespSchema])
async def select_user_more(q: str, request: Request):
    session = request.state.session
    async with session.begin():
        # stmt = select(User.id, User.email, User.username).where(
        #     or_(User.email.contains(q), User.username.contains(q))
        # ).order_by(User.id.desc()).limit(2)
        # result = await session.execute(stmt)
        # data_list = [row._asdict() for row in result]
        # return data_list


        stmt = select(User).where(
            or_(User.email.contains(q), User.username.contains(q))
        ).order_by(User.id.desc()).limit(3)
        result = await session.execute(stmt)
        return result.scalars()


@router.put('/update/{user_id}', response_model=UserRespSchema)
async def update_user_1(user_id: int, request: Request, item: UpdateUserReqSchema):
    session = request.state.session
    async with session.begin():
        stmt = select(User).where(User.id == user_id)
        result = await session.execute(stmt)
        user = result.scalars().first()
        user.email = item.email or user.email
        user.username = item.username or user.username
        user.password = item.password or user.password
        return user


@router.put('/update/new/{user_id}')
async def update_user_2(user_id: int, request: Request, item: UpdateUserReqSchema):
    session = request.state.session
    async with session.begin():
        update_data = {}
        if item.email:
            update_data["email"] = item.email
        if item.username:
            update_data["username"] = item.username
        if item.password:
            update_data["password"] = item.password
        stmt = update(User).where(User.id == user_id).values(**update_data)
        await session.execute(stmt)
        return {"message": "更新成功"}






